package service

import (
	"errors"
	"fitness/go-admin/internal/model"
	"fmt"
	"html"
	"log"
	"strings"
	"time"

	"gorm.io/gorm"
)

// ==================== 消息撤回 ====================

// RecallMessage 撤回消息（2分钟内）
func (s *ChatService) RecallMessage(messageID, userID uint) error {
	// 获取消息
	message, err := s.chatRepo.GetMessageByID(messageID)
	if err != nil {
		return errors.New("消息不存在")
	}

	// 验证权限：只能撤回自己的消息
	if message.SenderID == nil || *message.SenderID != userID {
		return errors.New("只能撤回自己的消息")
	}

	// 检查是否已撤回
	if message.IsRecalled {
		return errors.New("消息已撤回")
	}

	// 检查时间：只能撤回2分钟内的消息
	if time.Since(message.CreatedAt) > 2*time.Minute {
		return errors.New("只能撤回2分钟内的消息")
	}

	// 撤回消息
	if err := s.chatRepo.RecallMessage(messageID); err != nil {
		return err
	}

	// 通知对方消息已撤回
	session, _ := s.chatRepo.GetSessionByID(message.SessionID)
	if session != nil {
		s.notifyMessageRecalled(session, message)
	}

	return nil
}

// ==================== 离线消息推送 ====================

// GetOfflineMessages 获取离线消息（用户重连时调用）
func (s *ChatService) GetOfflineMessages(userID uint, lastSyncTime time.Time) ([]model.ChatMessage, error) {
	// 获取用户的所有活跃会话
	sessions, _, err := s.chatRepo.GetUserSessions(userID, "", 1, 100)
	if err != nil {
		return nil, err
	}

	var offlineMessages []model.ChatMessage

	// 遍历每个会话，获取离线消息
	for _, session := range sessions {
		// 获取该会话在指定时间后的未读消息
		messages, _, _ := s.chatRepo.GetSessionMessages(session.ID, 1, 100, 0)

		for _, msg := range messages {
			// 只推送在 lastSyncTime 之后且未读的消息，且不是用户自己发送的
			if msg.CreatedAt.After(lastSyncTime) && !msg.IsRead && (msg.SenderID == nil || *msg.SenderID != userID) {
				offlineMessages = append(offlineMessages, msg)
			}
		}
	}

	log.Printf("[离线消息] 用户 %d 获取到 %d 条离线消息", userID, len(offlineMessages))
	return offlineMessages, nil
}

// PushOfflineMessages 推送离线消息给用户（WebSocket 连接后调用）
func (s *ChatService) PushOfflineMessages(userID uint, client interface{}) error {
	// 获取最近1小时的离线消息
	lastSyncTime := time.Now().Add(-1 * time.Hour)
	offlineMessages, err := s.GetOfflineMessages(userID, lastSyncTime)
	if err != nil {
		return fmt.Errorf("获取离线消息失败: %v", err)
	}

	if len(offlineMessages) == 0 {
		return nil
	}

	// 构造 WebSocket 消息
	wsMsg := model.WSMessage{
		Type: "OFFLINE_MESSAGES",
		Data: map[string]interface{}{
			"count":    len(offlineMessages),
			"messages": offlineMessages,
		},
		Timestamp: time.Now(),
	}

	// 发送给用户
	s.wsManager.SendToUser(userID, wsMsg)

	log.Printf("[离线消息] 已向用户 %d 推送 %d 条离线消息", userID, len(offlineMessages))
	return nil
}

// ==================== 消息长度验证 ====================

// ValidateMessageContent 验证消息内容
func (s *ChatService) ValidateMessageContent(req *model.SendMessageReq) error {
	switch req.MessageType {
	case "TEXT":
		// 文本消息验证
		if len(strings.TrimSpace(req.Content)) == 0 {
			return errors.New("文本消息内容不能为空")
		}
		if len(req.Content) > 5000 {
			return errors.New("消息内容不能超过5000字符")
		}
		// XSS 防护：转义HTML
		req.Content = html.EscapeString(req.Content)

	case "IMAGE":
		// 图片消息验证
		if req.FileURL == "" {
			return errors.New("图片消息必须包含文件URL")
		}
		if req.ImageWidth <= 0 || req.ImageHeight <= 0 {
			return errors.New("图片必须包含有效的尺寸信息")
		}
		if req.ImageWidth > 10000 || req.ImageHeight > 10000 {
			return errors.New("图片尺寸超出限制（最大10000x10000）")
		}
		if req.FileSize > 10*1024*1024 { // 图片最大10MB
			return errors.New("图片大小不能超过10MB")
		}

	case "FILE":
		// 文件消息验证
		if req.FileURL == "" {
			return errors.New("文件消息必须包含文件URL")
		}
		if req.FileName == "" {
			return errors.New("文件消息必须包含文件名")
		}
		if req.FileSize <= 0 {
			return errors.New("文件大小必须大于0")
		}
		if req.FileSize > 50*1024*1024 { // 文件最大50MB
			return errors.New("文件大小不能超过50MB")
		}
		// 验证文件扩展名（可选，根据需求添加）
		allowedExts := []string{".jpg", ".jpeg", ".png", ".gif", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".zip"}
		isAllowed := false
		for _, ext := range allowedExts {
			if strings.HasSuffix(strings.ToLower(req.FileName), ext) {
				isAllowed = true
				break
			}
		}
		if !isAllowed {
			return errors.New("不支持的文件类型")
		}
	}

	return nil
}

// ==================== 会话超时自动关闭 ====================

// AutoCloseInactiveSessions 自动关闭长时间无活动的会话
func (s *ChatService) AutoCloseInactiveSessions(inactiveHours int) (int64, error) {
	// 计算超时时间（例如：24小时无活动）
	cutoffTime := time.Now().Add(-time.Duration(inactiveHours) * time.Hour)

	// 批量关闭超时会话
	count, err := s.chatRepo.CloseInactiveSessions(cutoffTime)
	if err != nil {
		return 0, fmt.Errorf("关闭超时会话失败: %v", err)
	}

	if count > 0 {
		log.Printf("[会话管理] 自动关闭了 %d 个超过 %d 小时无活动的会话", count, inactiveHours)
	}

	return count, nil
}

// ==================== 消息搜索 ====================

// SearchMessages 搜索消息（在会话中搜索关键词）
func (s *ChatService) SearchMessages(userID uint, sessionID uint, keyword string, page, pageSize int) ([]model.ChatMessage, int64, error) {
	// 验证权限
	session, err := s.chatRepo.GetSessionByID(sessionID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, 0, errors.New("会话不存在")
		}
		return nil, 0, errors.New("查询会话失败")
	}

	if session.MemberID != userID && (session.StaffID == nil || *session.StaffID != userID) {
		return nil, 0, errors.New("无权搜索此会话")
	}

	// 参数验证
	if page < 1 {
		page = 1
	}
	if pageSize < 1 || pageSize > 100 {
		pageSize = 20
	}

	// 搜索消息
	messages, total, err := s.chatRepo.SearchMessages(sessionID, keyword, page, pageSize)
	if err != nil {
		return nil, 0, fmt.Errorf("搜索消息失败: %v", err)
	}

	log.Printf("[消息搜索] 用户 %d 在会话 %d 搜索关键词 '%s'，找到 %d 条结果", userID, sessionID, keyword, total)
	return messages, total, nil
}

// ==================== 会话转接 ====================

// TransferSession 转接会话（客服A转给客服B）
func (s *ChatService) TransferSession(sessionID, fromStaffID, toStaffID uint) error {
	// 验证会话存在且属于当前客服
	session, err := s.chatRepo.GetSessionByID(sessionID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("会话不存在")
		}
		return errors.New("查询会话失败")
	}

	// 验证权限：只有当前负责的客服可以转接
	if session.StaffID == nil || *session.StaffID != fromStaffID {
		return errors.New("无权转接此会话")
	}

	// 验证目标客服存在
	_, err = s.userRepo.GetByID(toStaffID)
	if err != nil {
		return errors.New("目标客服不存在")
	}

	// TODO: 可以添加角色验证，确保目标用户是客服/教练/管理员

	// 执行转接
	if err := s.chatRepo.TransferSession(sessionID, fromStaffID, toStaffID); err != nil {
		return fmt.Errorf("转接会话失败: %v", err)
	}

	// 发送系统消息通知
	systemMsg := fmt.Sprintf("会话已转接至新客服（ID: %d）", toStaffID)
	s.SendSystemMessage(sessionID, systemMsg)

	// WebSocket 通知双方
	s.notifySessionTransferred(session, fromStaffID, toStaffID)

	log.Printf("[会话转接] 会话 %d 从客服 %d 转接到客服 %d", sessionID, fromStaffID, toStaffID)
	return nil
}

// notifySessionTransferred 通知会话已转接
func (s *ChatService) notifySessionTransferred(session *model.ChatSession, fromStaffID, toStaffID uint) {
	wsMsg := model.WSMessage{
		Type: "SESSION_TRANSFERRED",
		Data: map[string]interface{}{
			"sessionId":   session.ID,
			"fromStaffId": fromStaffID,
			"toStaffId":   toStaffID,
		},
		Timestamp: time.Now(),
	}

	// 通知会员、原客服、新客服
	recipients := []uint{session.MemberID, fromStaffID, toStaffID}
	s.wsManager.SendToUsers(recipients, wsMsg)
}

// ==================== WebSocket 通知增强 ====================

// notifyMessageRecalled 通知消息已撤回
func (s *ChatService) notifyMessageRecalled(session *model.ChatSession, message *model.ChatMessage) {
	// 构造撤回通知
	wsMsg := model.WSMessage{
		Type: "MESSAGE_RECALLED",
		Data: map[string]interface{}{
			"sessionId": session.ID,
			"messageId": message.ID,
		},
		Timestamp: time.Now(),
	}

	// 发送给会话相关的用户
	recipients := []uint{session.MemberID}
	if session.StaffID != nil {
		recipients = append(recipients, *session.StaffID)
	}

	s.wsManager.SendToUsers(recipients, wsMsg)
}
